// client.cpp
#define _WIN32_DCOM
#include <olectl.h>
#include <conio.h>
#include <iostream.h>
#include "Component\component.h"

class CSink : public IOutGoing
{
public:
	// IUnknown
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();
	HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

	// IOutGoing
	HRESULT __stdcall GotMessage(int Message);

	CSink() : m_cRef(0) { }
	~CSink() { }

private:
	long m_cRef;
};

ULONG CSink::AddRef()
{
	return ++m_cRef;
}

ULONG CSink::Release()
{
	if(--m_cRef != 0)
		return m_cRef;
	delete this;
	return 0;
}

HRESULT CSink::QueryInterface(REFIID riid, void** ppv)
{
	if(riid == IID_IUnknown)
	{
		*ppv = (IUnknown*)this;
	}
	else if(riid == IID_IOutGoing)
	{
		cout << "Client: CSink::QueryInterface() for IOutGoing" << endl;
		*ppv = (IOutGoing*)this;
	}
	else 
	{
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	AddRef();
	return S_OK;
}

HRESULT CSink::GotMessage(int Message)
{
	if(Message == (int)'b' || Message == (int)'B')
		PlaySound("BrockschmidtQuack", NULL, SND_RESOURCE|SND_ASYNC);
	cout << "CSink::GotMessage is " << (char)Message << endl;
	return S_OK;
}

void main()
{
	cout << "Client: Calling CoInitialize()" << endl;
	CoInitializeEx(NULL, COINIT_MULTITHREADED);
	
	IUnknown* pUnknown;
	cout << "Client: Calling CoCreateInstance()" << endl;
	CoCreateInstance(CLSID_InsideCOM, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);

	ISum* pSum;
	cout << "Client: Calling QueryInterface() for ISum on " << pUnknown << endl;
	HRESULT hr = pUnknown->QueryInterface(IID_ISum, (void**)&pSum);
	if(FAILED(hr))
		cout << "QueryInterface FAILED" << endl;

	int sum;
	pSum->Sum(17, 2, &sum);
	cout << "pSum->Sum(17, 2) = " << sum << endl;

	IConnectionPointContainer* pConnectionPointContainer;
	hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
	if(SUCCEEDED(hr))
	{
		IConnectionPoint* pConnectionPoint;
		hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint);
		cout << "FindConnectionPoint returns " << hr << " pConnectionPoint = " << pConnectionPoint << endl;

		CSink* mySink = new CSink;
		DWORD dwCookie;
		pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie);

		cout << "Press any key to exit" << endl;
		_getch();

		pConnectionPoint->Unadvise(dwCookie);
		pConnectionPoint->Release();
		pConnectionPointContainer->Release();
	}

	cout << "Client: Calling Release() for pSum" << endl;
	hr = pSum->Release();

	cout << "Client: Calling Release() for pUnknown" << endl;
	hr = pUnknown->Release();

	cout << "Client: Calling CoUninitialize()" << endl;
	CoUninitialize();
}